<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> 
<html>
<head>
<title>Shapes and fills in PyCairo</title>
<link rel="stylesheet" href="/cfg/format.css" type="text/css">
<meta http-equiv="content-type" content="text/html; charset=utf-8">
<meta name="keywords" content="PyCairo, graphics, Python, shapes, fills">
<meta name="description" content="In this tutorial, we will work with shapes and 
fills in PyCairo">
<meta name="language" content="en">
<meta name="author" content="Jan Bodnar">
<meta name="distribution" content="global">

<script type="text/javascript" src="/lib/jquery.js"></script>
<script type="text/javascript" src="/lib/common.js"></script>

</head>

<body>

<div class="container2">

<div id="wide_ad" class="ltow">
<script type="text/javascript"><!--
google_ad_client = "pub-9706709751191532";
/* 160x600, August 2011 */
google_ad_slot = "2484182563";
google_ad_width = 160;
google_ad_height = 600;
//-->
</script>
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script>
</div>

<div class="content2">


<a href="/" title="Home">Home</a>&nbsp;
<a href="..">Contents</a>


<h1>Shapes and fills in PyCairo</h1>


<p>
In this part of the PyCairo tutorial, we will create some basic and more 
advanced shapes. We will fill them with solid colors, patterns and gradients. 
Gradients will be covered in a separate chapter.
</p>

<div class="big_hor">
<script type="text/javascript"><!--
google_ad_client = "ca-pub-9706709751191532";
/* big_horizontal */
google_ad_slot = "2904953388";
google_ad_width = 728;
google_ad_height = 90;
//-->
</script>
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script>
</div>


<h2>Basic shapes</h2>

<p>
PyCairo has some basic methods to create simple shapes.
</p>

<pre class="code">
def on_draw(self, wid, cr):

    cr.set_source_rgb(0.6, 0.6, 0.6)

    cr.rectangle(20, 20, 120, 80)
    cr.rectangle(180, 20, 80, 80)
    cr.fill()

    cr.arc(330, 60, 40, 0, 2*math.pi)
    cr.fill()
    
    cr.arc(90, 160, 40, math.pi/4, math.pi)
    cr.fill()

    cr.translate(220, 180)
    cr.scale(1, 0.7)
    cr.arc(0, 0, 50, 0, 2*math.pi)
    cr.fill()
</pre>

<p>
In this example, we will create a rectangle, a square, a circle, an arc 
and an ellipse.
</p>

<pre class="explanation">
cr.rectangle(20, 20, 120, 80)
cr.rectangle(180, 20, 80, 80)
</pre>

<p>
The <code>rectangle()</code> method is used to create both 
squares and rectangles. A square is just a specific type of 
a rectangle.
</p>

<pre class="explanation">
cr.arc(330, 60, 40, 0, 2*math.pi)
</pre>

<p>
This line creates a circle.
</p>

<pre class="explanation">
cr.arc(90, 160, 40, math.pi/4, math.pi)
</pre>

<p>
Here we draw an arc, a portion of a circle.
</p>


<pre class="explanation">
cr.scale(1, 0.7)
cr.arc(0, 0, 50, 0, 2*math.pi)
</pre>

<p>
We use the <code>scale()</code> and the <code>arc()</code> methods to create 
an ellipse.
</p>


<img src="/img/gfx/pycairo/basicshapes.png" alt="Basic Shapes">
<div class="figure">Figure: Basic Shapes</div>


<p>
Other shapes can be created using a combination of basic primitives.
</p>


<pre class="code">
#!/usr/bin/python

'''
ZetCode PyCairo tutorial 

This code example draws another
three shapes in PyCairo.

author: Jan Bodnar
website: zetcode.com 
last edited: August 2012
'''

from gi.repository import Gtk
import cairo


class cv(object):
    
    points = ( 
        ( 0, 85 ), 
        ( 75, 75 ), 
        ( 100, 10 ), 
        ( 125, 75 ), 
        ( 200, 85 ),
        ( 150, 125 ), 
        ( 160, 190 ),
        ( 100, 150 ), 
        ( 40, 190 ),
        ( 50, 125 ),
        ( 0, 85 )
    )


class Example(Gtk.Window):

    def __init__(self):
        super(Example, self).__init__()
        
        self.init_ui()
        
        
    def init_ui(self):    

        darea = Gtk.DrawingArea()
        darea.connect("draw", self.on_draw)
        self.add(darea)

        self.set_title("Complex shapes")
        self.resize(460, 240)
        self.set_position(Gtk.WindowPosition.CENTER)
        self.connect("delete-event", Gtk.main_quit)
        self.show_all()
        
    
    def on_draw(self, wid, cr):

        cr.set_source_rgb(0.6, 0.6, 0.6)
        cr.set_line_width(1)

        for i in range(10):
            cr.line_to(cv.points[i][0], cv.points[i][1])

        cr.fill()

        cr.move_to(240, 40)
        cr.line_to(240, 160)
        cr.line_to(350, 160)
        cr.fill()

        cr.move_to(380, 40)
        cr.line_to(380, 160)
        cr.line_to(450, 160)
        cr.curve_to(440, 155, 380, 145, 380, 40)
        cr.fill()
        
    
def main():
    
    app = Example()
    Gtk.main()
        
        
if __name__ == "__main__":    
    main()
</pre>

<p>
In this example, we create a star object, a triangle and a modified triangle. 
These objects are created using lines and one curve.
</p>

<pre class="explanation">
for i in range(10):
    cr.line_to(cv.points[i][0], cv.points[i][1])

cr.fill()
</pre>

<p>
The star is drawn by joining all the points that are in the points tuple. 
The <code>fill()</code> method fills the star object with the current colour.
</p>

<pre class="explanation">
cr.move_to(240, 40)
cr.line_to(240, 160)
cr.line_to(350, 160)
cr.fill()
</pre>

<p>
These lines create a triangle. The last two points are automatically 
joined by PyCairo.
</p>

<pre class="explanation">
cr.move_to(380, 40)
cr.line_to(380, 160)
cr.line_to(450, 160)
cr.curve_to(440, 155, 380, 145, 380, 40)
cr.fill()
</pre>

<p>
The modified triangle is a simple combination of two lines and one curve.
</p>


<img src="/img/gfx/pycairo/complexshapes.png" alt="Comlex shapes">
<div class="figure">Figure: Complex shapes</div>


<h2>Fills</h2>

<p>
Fills fill the interiors of shapes. Fills can be solid colors, patters or gradients.
</p>



<h3>Solid colours</h3>

<p>
A colour is an object representing a combination of Red, Green, and Blue (RGB) 
intensity values. PyCairo valid RGB values are in the range 0 to 1. 
</p>

<pre class="code">
def on_draw(self, wid, cr):

    cr.set_source_rgb(0.2, 0.23, 0.9)
    cr.rectangle(10, 15, 90, 60)
    cr.fill()
        
    cr.set_source_rgb(0.9, 0.1, 0.1)
    cr.rectangle(130, 15, 90, 60)
    cr.fill()

    cr.set_source_rgb(0.4, 0.9, 0.4)
    cr.rectangle(250, 15, 90, 60)
    cr.fill()           
</pre>

<p>
In the example we draw four coloured rectangles
</p>

<pre class="explanation">
cr.set_source_rgb(0.2, 0.23, 0.9)
cr.rectangle(10, 15, 90, 60)
cr.fill()
</pre>

<p>
The <code>set_source_rgb()</code> method sets the source to an opaque color. 
The parameters are the Red, Green, Blue intensity values. 
The source is used to fill the interior of a rectangle by calling the 
<code>fill()</code> method.
</p>


<img src="/img/gfx/pycairo/colours.png" alt="Solid colors">
<div class="figure">Figure: Solid colors</div>


<h3>Patterns</h3>

<p>
Patterns are complex graphical objects that can be used to fill shapes.
</p>

<pre class="code">
#!/usr/bin/python

'''
ZetCode PyCairo tutorial 

This program shows how to work
with patterns in PyCairo.

author: Jan Bodnar
website: zetcode.com 
last edited: August 2012
'''


from gi.repository import Gtk
import cairo


class Example(Gtk.Window):

    def __init__(self):
        super(Example, self).__init__()
        
        self.init_ui()
        self.create_surpat()
        
        
    def init_ui(self):    

        darea = Gtk.DrawingArea()
        darea.connect("draw", self.on_draw)
        self.add(darea)

        self.set_title("Patterns")
        self.resize(300, 290)
        self.set_position(Gtk.WindowPosition.CENTER)
        self.connect("delete-event", Gtk.main_quit)
        self.show_all()
        

    def create_surpat(self):
        
        sr1 = cairo.ImageSurface.create_from_png("blueweb.png")
        sr2 = cairo.ImageSurface.create_from_png("maple.png")
        sr3 = cairo.ImageSurface.create_from_png("crack.png")
        sr4 = cairo.ImageSurface.create_from_png("chocolate.png")
        
        self.pt1 = cairo.SurfacePattern(sr1)
        self.pt1.set_extend(cairo.EXTEND_REPEAT)
        self.pt2 = cairo.SurfacePattern(sr2)
        self.pt2.set_extend(cairo.EXTEND_REPEAT)
        self.pt3 = cairo.SurfacePattern(sr3)
        self.pt3.set_extend(cairo.EXTEND_REPEAT)
        self.pt4 = cairo.SurfacePattern(sr4)
        self.pt4.set_extend(cairo.EXTEND_REPEAT)        
        
        
    def on_draw(self, wid, cr):

        cr.set_source(self.pt1)
        cr.rectangle(20, 20, 100, 100)
        cr.fill()

        cr.set_source(self.pt2) 
        cr.rectangle(150, 20, 100, 100)
        cr.fill()

        cr.set_source(self.pt3)
        cr.rectangle(20, 140, 100, 100)
        cr.fill()

        cr.set_source(self.pt4)
        cr.rectangle(150, 140, 100, 100)
        cr.fill()
        
    
def main():
    
    app = Example()
    Gtk.main()
        
        
if __name__ == "__main__":    
    main()
</pre>

<p>
In this example we draw four rectangles. This time we fill them with some patterns. 
We use four pattern images from the <b>Gimp</b> image manipulation program. 
We must retain the original size of those patterns because we are going to tile them.
</p>

<p>
We create image surfaces outside the <code>draw()</code> method. 
It would not be efficient to read from harddisk each time the window needs to be redrawn.
</p>

<pre class="explanation">
sr1 = cairo.ImageSurface.create_from_png("blueweb.png")
</pre>

<p>
An image surface is created from a PNG image.
</p>

<pre class="explanation">
self.pt1 = cairo.SurfacePattern(sr1)
self.pt1.set_extend(cairo.EXTEND_REPEAT)
</pre>

<p>
A pattern is created from the surface. We set the mode to 
<code>cairo.EXTEND_REPEAT</code> which causes the 
pattern to be tiled by repeating. 
</p>

<pre class="explanation">
cr.set_source(self.pt1)
cr.rectangle(20, 20, 100, 100)
cr.fill()
</pre>

<p>
Here we draw our first rectangle. The <code>set_source()</code> method tells 
the Cairo context to use a pattern as a source for drawing. The image patterns may not 
fit exactly the shape. The <code>rectangle()</code> creates a rectangular path.
Finally, the <code>fill()</code> method fills the path with the source.
</p>


<p>
This chapter covered PyCairo shapes and fills.
</p>


<div class="center"> 
<script type="text/javascript"><!--
google_ad_client = "pub-9706709751191532";
/* horizontal */
google_ad_slot = "1734478269";
google_ad_width = 468;
google_ad_height = 60;
//-->
</script> 
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js"> 
</script> 
</div> 
<br>


<div class="botNav, center">
<span class="botNavItem"><a href="/">Home</a></span> ‡ <span class="botNavItem"><a href="..">Contents</a></span> ‡ 
<span class="botNavItem"><a href="#">Top of Page</a></span>
</div>


<div class="footer">
<div class="signature">
<a href="/">ZetCode</a> last modified September 2, 2012  <span class="copyright">&copy; 2007 - 2013 Jan Bodnar</span>
</div>
</div>

</div> <!-- content -->

</div> <!-- container -->

</body>
</html>
